package scriptEngine

import (
	"encoding/base64"
	"errors"
	"fmt"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Hex"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Json"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Map"
	"github.com/dop251/goja"
	"strings"
)

type Decoder struct {
	engine *goja.Runtime // 执行引擎
	script string        // 解码器脚本

	Manufacturer string // 设备厂商名称
	DeviceType   string // 设备类型名
	OperateName  string // 操作命令
}

func (e *Decoder) Decode(subscribe string, topic string, payload []byte) (recordList []map[string]interface{}, err error) {
	// 定义一个最终的异常拦截，用来防止可能的代码BUG
	defer func() {
		if r := recover(); r != nil {
			recordList = nil
			err = errors.New(fmt.Sprintf("捕获到异常:%v", r))
		}
	}()

	// 转换成文本
	message := make(map[string]interface{})
	message["topic"] = topic
	message["subscribe"] = subscribe
	message["payload"] = e.encodeMessage(payload)
	jsn := Json.BuildJson(message)

	// 执行JSP脚本中的函数
	decode, ok := goja.AssertFunction(e.engine.Get("getServiceKey"))
	if !ok {
		return nil, errors.New("找不到getServiceKey()函数")
	}

	// 执行函数
	res, err := decode(goja.Undefined(), e.engine.ToValue(jsn))
	if err != nil {
		return nil, err
	}

	// 字符串的处理
	jsn = strings.TrimSpace(res.String())
	if len(jsn) == 0 {
		return nil, errors.New("无效的JSON格式")
	}

	// JSON格式的转换
	list := make([]map[string]interface{}, 0)
	if jsn[0] == '{' {
		data := Json.BuildMapByJson(jsn)
		list = append(list, data)
	} else if jsn[0] == '[' {
		list = Json.BuildMapListByJson(jsn)
	}

	// 对返回结果的检查和重新组织
	recordList = make([]map[string]interface{}, 0)
	for _, data := range list {
		// 必填参数：解码器会检查数据的有效性
		channelKey := Map.GetString(data, "channelKey", "")
		channelParam := Map.GetMap(data, "channelParam", make(map[string]interface{}))
		deviceKey := Map.GetString(channelParam, "deviceKey", "")
		if channelKey == "" || len(channelParam) == 0 || deviceKey == "" {
			return nil, errors.New("解码器返回的格式不正确")
		}

		// 必填参数：解码器会检查数据的有效性
		manufacturer := Map.GetString(data, "manufacturer", "")
		deviceType := Map.GetString(data, "deviceType", "")
		deviceName := Map.GetString(data, "deviceName", "")
		deviceParam := Map.GetMap(data, "deviceParam", make(map[string]interface{}))

		// 选填参数：自定义参数
		pdu, err := e.getPayload(data)
		if err != nil {
			return nil, errors.New("解码器返回的格式不正确")
		}
		if pdu == nil {
			pdu = payload
		}

		record := make(map[string]interface{})
		record["deviceKey"] = deviceKey
		record["channelKey"] = channelKey
		record["channelParam"] = channelParam
		record["manufacturer"] = manufacturer
		record["deviceType"] = deviceType
		record["deviceName"] = deviceName
		record["deviceParam"] = deviceParam
		record["payload"] = pdu

		recordList = append(recordList, record)
	}

	return recordList, nil
}

func (e *Decoder) encodeMessage(payload []byte) interface{} {
	format, ok := goja.AssertFunction(e.engine.Get("format"))
	if !ok {
		return Hex.EncodeToString(payload)
	}
	// 执行函数
	res, err := format(goja.Undefined())
	if err != nil {
		return Hex.EncodeToString(payload)
	}

	if res.String() == "json" {
		jsn := string(payload)
		jsn = strings.TrimSpace(jsn)
		if jsn[0] == '[' {
			return Json.BuildMapListByJson(jsn)
		} else {
			return Json.BuildMapByJson(jsn)
		}
	}

	return Hex.EncodeToString(payload)
}

func (e *Decoder) getPayload(data map[string]interface{}) (interface{}, error) {
	rtnPayload := Map.GetMap(data, "payload", make(map[string]interface{}))
	val, ok := rtnPayload["base64"]
	if ok {
		return base64.StdEncoding.DecodeString(val.(string))
	}
	val, ok = rtnPayload["hex"]
	if ok {
		return Hex.DecodeString(val.(string)), nil
	}
	val, ok = rtnPayload["json"]
	if ok {
		return val, nil
	}

	return nil, nil
}
